grammar Piano;


options {
backtrack = true;
language = C;
}

tokens {
RPAR=')';
LPAR='(';
ASSIGN=':=';
SEMI=';';
ADD='+';
SUB='-';
DIV='/';
MUL='*';
GREATER='>';
LESS='<';
EQUALITY='=';
AND='AND';
OR='OR';
NOT='NOT';
INTERSECTION='INTER';
UNION='UNION';
COMPLIMENT='COMP';
MEMBERSHIP='EXIST';
THEREEXIST='THEREEXISTS';
CARTPRO='CPRODUCT';
SCALARPRO='SPRODUCT';
CARDINALITY='CARDIN';
SUBSET='ISSUB';
EQUAL='ISEQUAL';
COMPOSITION='COMPO';
PROJECTION='PROJ';
SUBSTITUTION='SUBS';
FOREVERY='FOREVERY';
IN='IN';
ST='SUCHTHAT';
}


@parser::includes {
/** \file Piano.g\n * \author Farah Charab\n Rafah El-Khatib\n Abbas Bazzi\n \brief This is our antlr file.*/
   #include <Graph.h>
   #include <iostream>
   #include <string>
extern __NOT g;
}
	
/*
@lexer::includes
{

#include <iostream>
using namespace std;

}
*/

@parser::header {
#include <iostream>
   #include <string>
}

prog    :        statm+;

statm   :       NEWLINE
        |       type WORD SEMI {
			g.setType((char*)$WORD.text->chars,g.getNumber((char*)$type.text->chars));
			}
        |       (('INT')?(word1=WORD opassign=ASSIGN{
			g.setType((char*)$word1.text->chars,3);
		}
		))
		expr4 SEMI{
			g.CreateAssignment((char*)$word1.text->chars,(char*)$opassign.text->chars,$expr4.value);
		}
	|       expr4 SEMI
	|	expr3 SEMI
	|	(exp1=expr0 equsub exp2=expr0){
			g.RootReturn($equsub.value,$exp1.value,$exp2.value);
		} 
		SEMI
	|	wordortuple MEMBERSHIP exp2=expr1{
			g.natAssig=g.RootReturn((char*)$MEMBERSHIP.text->chars,$wordortuple.value,$exp2.value);
		} 
		SEMI
        |       ('REAL')?(word5=WORD opassign4=ASSIGN{
			g.setType((char*)$word5.text->chars,4);
		}) 
		expr5 SEMI{
			g.CreateAssignment((char*)$word5.text->chars,(char*)$opassign4.text->chars,$expr5.value);
		} 
	|       ('INT')?(word51=WORD opassign41=ASSIGN{
			g.setType((char*)$word51.text->chars,3);
		}) 
		expr5 SEMI{
			g.CreateAssignment((char*)$word51.text->chars,(char*)$opassign41.text->chars,$expr5.value);
		}
        |       ('SET')?(word6=WORD opassign5=ASSIGN{
			g.setType((char*)$word6.text->chars,5);
		}) 
		expr0 SEMI{
			g.CreateAssignment((char*)$word6.text->chars,(char*)$opassign5.text->chars,$expr0.value);
		}
        |       COMMENT
	|	('TUPLE')?(word7=WORD opassign6=ASSIGN{
			g.setType((char*)$word7.text->chars,7);
		})
		(word8=WORD{
			g.setType((char*)$word8.text->chars,7);
			g.CreateAssignment((char*)$word7.text->chars,(char*)$opassign6.text->chars,(char*)$word8.text->chars);
		}) 
		SEMI
	|	('TUPLE')?(word7=WORD opassign6=ASSIGN{
			g.setType((char*)$word7.text->chars,7);
		})
		(tuple1=TUPLE{
			g.setType((char*)$tuple1.text->chars,1);
			g.CreateAssignment((char*)$word7.text->chars,(char*)$opassign6.text->chars,(char*)$tuple1.text->chars);
		}) 
		SEMI
        |       ('MAP')?(word9=WORD ASSIGN{
			g.setType((char*)$word9.text->chars,6);
		})
		(word10=WORD{
			g.setType((char*)$word10.text->chars,6);
			g.CreateAssignment((char*)$word9.text->chars,(char*)$ASSIGN.text->chars,(char*)$word10.text->chars);
		}) 
		SEMI
	|	('MAP')?(word9=WORD ASSIGN{
			g.setType((char*)$word9.text->chars,6);
		})
		(MAP{
			g.setType((char*)$MAP.text->chars,1);
			g.CreateAssignment((char*)$word9.text->chars,(char*)$ASSIGN.text->chars,(char*)$MAP.text->chars);
		}) 
		SEMI
	|       ('MAP')?(word9=WORD ASSIGN{
			g.setType((char*)$word9.text->chars,6);
		})
		(word101=mapword word102=COMPOSITION word103=mapword{
			g.natAssig=g.RootReturn((char *)$word102.text->chars,$word101.value,$word103.value);
			g.CreateAssignment((char*)$word9.text->chars,(char*)$ASSIGN.text->chars,g.natAssig);
		}) 
		SEMI
	|       v4=THEREEXIST v5=WORD IN v6=expr1 v7=ST v8=stcondition{
			g.natAssig=g.RootReturn((char *)$v4.text->chars,$v6.value,$v8.value);
		} 
		SEMI
	|       v4=FOREVERY v5=WORD IN v6=expr1 v8=stcondition{
			g.natAssig=g.RootReturn((char *)$v4.text->chars,$v6.value,$v8.value);
		} 
		SEMI
        |       ('SET')?(word11=WORD opassign7=ASSIGN{
			g.setType((char*)$word11.text->chars,5);
		}) 
		(w3=mapword w4=PROJECTION w5=expr0{
			g.natAssig=g.RootReturn((char *)$w4.text->chars,$w3.value,$w5.value);
			}) 
		SEMI {
			g.CreateAssignment((char *)$word11.text->chars,(char *)$opassign7.text->chars,g.natAssig);
		}
	|	('SET')?(word11=WORD opassign7=ASSIGN{
			g.setType((char*)$word11.text->chars,5);
		})
		(exp4=expr0 w7=PROJECTION w8=mapword{
			g.natAssig=g.RootReturn((char *)$w7.text->chars,$exp4.value,$w8.value);
		}) 
		SEMI {
			g.CreateAssignment((char *)$word11.text->chars,(char *)$opassign7.text->chars,g.natAssig);
		}

      |       ('SET')?(word12=WORD opassign8=ASSIGN{
			g.setType((char*)$word12.text->chars,5);
		}) 
		(f3=mapword f4=SUBSTITUTION exp5=expr0{
			g.natAssig=g.RootReturn((char *)$f4.text->chars,$f3.value,$exp5.value);
		}) 
		SEMI {
			g.CreateAssignment((char*)$word12.text->chars,(char*)$opassign8.text->chars,g.natAssig);
		};  
    
expr0 returns [char* value]        : expr1{
			$value = $expr1.value;
		}
		|SET{
			$value=(char *)$SET.text->chars;
			g.setType((char*)$SET.text->chars,1);
		};       
expr1   returns [char* value]      : u=newexpr2 {
			g.tempSetRel=$u.value;
		} 
		(setrel v=newexpr2{
			g.tempSetRel=g.RootReturn($setrel.value,g.tempSetRel,$v.value);
		})*{
			$value=g.tempSetRel;
		};
// relation between two sets or just one set
setrel returns [char* value]       : (UNION{
			$value = (char *)$UNION.text->chars;
		}
		|INTERSECTION{
			$value = (char *)$INTERSECTION.text->chars;
		}
		|CARTPRO{
			$value = (char *)$CARTPRO.text->chars;
		});

newexpr2  returns [char* value]    : a=expr2{
			$value=$a.value;
		}
		|	(expscal SCALARPRO b=expr2){
			$value=g.RootReturn((char*)$SCALARPRO.text->chars,$expscal.value,(char*)$b.value);
		};	

expr2     returns [char* value]    : compw{
			$value=$compw.value;
		}
		|(expscal SCALARPRO b=WORD){
			$value=g.RootReturn((char*)$SCALARPRO.text->chars,$expscal.value,(char*)$b.text->chars);
		}
		|a=WORD {
			$value=(char *)$a.text->chars;
		};
compw returns [char *value]        : COMPLIMENT a=expr1 IN b=expr1{
			$value=g.RootReturn((char*)$COMPLIMENT.text->chars,$a.value,$b.value);
		};
expscal returns [char* value]      : (WORD{
			$value=(char*)$WORD.text->chars;
		}
		| expr5{
			$value=$expr5.value;
		});
// how to express a set

expr3 returns [char* value]        : a=expr5 gle b=expr5{
			$value=g.RootReturn($gle.value, $a.value, $b.value);
		};
gle returns [char* value]          : (GREATER{
			$value=(char *)$GREATER.text->chars;
		}
		|LESS{
			$value=(char *)$LESS.text->chars;
		}
		|EQUALITY{
			$value=(char *)$EQUALITY.text->chars;
		});
//using AND OR NOT
// comparisons giving boolean values
equsub returns [char* value]      : (EQUAL{
			$value=(char *)$EQUAL.text->chars;
		}
		|SUBSET{
			$value=(char *)$SUBSET.text->chars;
		});
wordortuple returns [char* value] : (WORD{
			$value=(char *)$WORD.text->chars;
		}
		|TUPLE{
			$value=(char *)$TUPLE.text->chars;
			g.setType((char*)$TUPLE.text->chars,1);
		});
expr4       returns [char* value] : a=negexpr{
			g.tempAndNotRel=$a.value;
		}
		(andornot b=negexpr{
			g.tempAndNotRel=g.RootReturn($andornot.value,g.tempAndNotRel,$b.value);
		})*{
			$value=g.tempAndNotRel;
		};
andornot returns [char * value]   : (AND{
			$value=(char*)$AND.text->chars;
		}
		|NOT{
			$value=(char*)$NOT.text->chars;
		}|
		OR{
			$value=(char*)$OR.text->chars;
		});
negexpr returns [char* value]     : (NOT{
			g.isNot=1;
		})? 
		wrdnat{
			if(g.isNot==0){
				$value=$wrdnat.value;
			} 
			else {
				$value = g.CardinAssig((char*)$NOT.text->chars,$wrdnat.value);
			}
			g.isNot=0;
		};
wrdnat returns [char* value]      : (WORD{
			$value=(char*)$WORD.text->chars;
		}
		|INT{
			$value=(char*)$INT.text->chars;
			g.setType((char*)$INT.text->chars,1);
		});
	
memorforevery returns [char * value] : THEREEXIST {
			$value=(char *)$THEREEXIST.text->chars;
		}
		| FOREVERY{
			$value=(char *)$FOREVERY.text->chars;
		};
wordnatreal returns [char * value] : (REAL{
			$value=(char *)$REAL.text->chars;
			g.setType((char*)$REAL.text->chars,1);
		}
		|INT{
			$value=(char *)$INT.text->chars;
			g.setType((char*)$INT.text->chars,1);
		}
		|WORD{
			$value=(char *)$WORD.text->chars;
		});
	
stcondition returns [char * value] : w=WORD{
			g.setType((char*)$WORD.text->chars,3);
		} 
		((a=gle b=wordnatreal{
			$value=g.RootReturn($a.value,(char *)$w.text->chars,$b.value);
		})
		|(c=EQUALITY d=TUPLE{
			$value=g.RootReturn((char*)$c.text->chars,(char *)$w.text->chars,(char*)$d.text->chars);
			g.setType((char*)$TUPLE.text->chars,7);
		}));

mapword returns [char * value]     : (MAP{
			g.setType((char*)$MAP.text->chars,1);
			$value=(char *)$MAP.text->chars;
		}
		|WORD{
			$value=(char *)$WORD.text->chars;
		});
expr5   returns [char * value]    : a=multExpr{
			g.tempAddRel=$a.value;
		}
		(addorsub b=multExpr{
			g.tempAddRel=g.RootReturn((char*)$addorsub.text->chars,g.tempAddRel,$b.value);
		})*{
			$value=g.tempAddRel;
		};
addorsub returns [char *value]    : (ADD{
			$value=(char*)$ADD.text->chars;
		}
		|SUB{
			$value=(char*)$SUB.text->chars;
		});

multExpr returns [char * value ]  : a=atom{
			g.tempMulRel=$a.value;
		}(mulordiv b=atom {
			g.tempMulRel=g.RootReturn ($mulordiv.value,g.tempMulRel,$b.value);})*{$value=g.tempMulRel;
		};
mulordiv returns [char *value]    : (MUL{
			$value=(char*)$MUL.text->chars;
		}|DIV{
			$value=(char*)$DIV.text->chars;
		});
	
atom  returns [char* value]     : (INT{
			$value=(char*)$INT.text->chars;
			g.setType((char*)$INT.text->chars,1);
		})
		|(REAL{
			$value=(char*)$REAL.text->chars;
			g.setType((char*)$REAL.text->chars,1);
		})
		|(WORD{
			$value=(char*)$WORD.text->chars;

		})
		|(cardinassig {
			$value = $cardinassig.value;
		});
// the above three terms give priority to multiplication/division over addition/subtraction
// in algebraic statements
cardinassig returns [char * value]: CARDINALITY expr1{
			$value = g.CardinAssig((char*)$CARDINALITY.text->chars,$expr1.value);
		};
type        :        'SET'
        |        'TUPLE'
        |        'RELATION'
        |        'MAP'
        |        'INT'
        |        'REAL';



WORD  :        ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
      ;

INT   :        ('-')?('0'..'9')+
      ;

REAL  : ('-')?('0'..'9')+ '.' ('0'..'9')+ EXPONENT?
    |   ('-')?'.' ('0'..'9')+ EXPONENT?
    |   ('-')?('0'..'9')+ EXPONENT
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :   
( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;
NEWLINE      :        '\r'?'\n';


TUPLE        :        ('[')((INT(','INT)*) |(REAL(','REAL)*) | (WORD(','WORD)*))(']');

SET          :        ('{')(TUPLE(','TUPLE)*)?('}');

RELATION:        TUPLE'->'TUPLE;

MAP          :        ('<'('('RELATION')'(',''('RELATION')')*)'>');

fragment
EXPONENT     : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
